#include "MainMenu.h"
#include "Level1.h"
#include "OptionsMenu.h"
#include "GLUtils.h"
#include "GLFont2D.h"
#include "Transformation.h"
#include "PlainTexture.h"
#include "Exception.h"
#include "Logger.h"

using namespace game_engine;
using namespace game_engine::utils;
using namespace game_engine::open_gl;
using namespace game_engine::gui;
using namespace game_engine::components;

///////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
///////////////////////////////////////////////////////////////////////////////

MainMenu::MainMenu(void)
    : Scene("MainMenu"), _btnPlay(NULL), _btnOptions(NULL), 
    _btnExit(NULL)
{
    _widgets.clear();
    _btnConnections.clear();
}

MainMenu::~MainMenu(void)
{
}

///////////////////////////////////////////////////////////////////////////////
// Other public methods
///////////////////////////////////////////////////////////////////////////////

const BOOL MainMenu::initialize(void)
{
    BOOL ok = true;
   
    try
    {
        // Create the objects
        createObjects();

        // Initialize all game objects
        initGameObjects();

        // Initialize the scene manager
        //sceneManager.initialize();

        // This is where all connections to signals are defined
        boost::signals2::connection c;
        c = _btnPlay->connect(_btnPlay->signalClicked(), boost::bind(&MainMenu::onPlay, this, _1));
        _btnConnections.push_back(c);
        c = _btnOptions->connect(_btnOptions->signalClicked(), boost::bind(&MainMenu::onOptions, this, _1));
        _btnConnections.push_back(c);
        c = _btnExit->connect(_btnExit->signalClicked(), boost::bind(&MainMenu::onExit, this, _1));
        _btnConnections.push_back(c);

        // Graphics initialization
        GLUtils::commonLevelInit();
        GLUtils::levelInit(resolution.getWidth(), resolution.getHeight()); 
    } catch (exception &e) {
        Logger::FATAL(GAME_LOG, string("Error during MainMenu initialization : ") + 
            e.what());
        return false;
    }

    nextScene = this;

    return ok;
}

const BOOL MainMenu::update(const FLOAT32 time)
{
    // Update the whole scene
    BOOL ok = true;
    try
    {
        updateGameObjects(time);
    } catch (exception &e)
    {
        string err("Error during scene update: ");
        err.append(e.what());
        Logger::ERR(GAME_LOG, err);
        return false;
    }

  	//if(keys[ESC_KEY])
   // {
   //     ok = false;
   //     keys[ESC_KEY] = false;
   //     nextScene = NULL;
   // }

    return ok;
}

void MainMenu::finalize(void)
{
    try
    {
        // Finalize game objects
        finishGameObjects();

        // This is where all connections to signals are destroyed
        vector<boost::signals2::connection>::iterator it;
        for (it=_btnConnections.begin(); it<_btnConnections.end(); it++)
        {
            (*it).disconnect();
        }

    } catch (exception &e)
    {
        string err("Error during scene finalization: ");
        err.append(e.what());
        Logger::ERR(GAME_LOG, err);
        throw RuntimeException(err);
    }
}

///////////////////////////////////////////////////////////////////////////////
// Slots
///////////////////////////////////////////////////////////////////////////////

void MainMenu::onPlay(BOOL clicked)
{
    if (clicked)
    {
        setMenuFocus(_btnPlay);
        Level1 *level1 = new Level1();
        level1->setResolution(Size(512, 640));
        nextScene = level1;
    }
}

void MainMenu::onOptions(BOOL clicked)
{
    if (clicked)
    {
        setMenuFocus(_btnOptions);
        OptionsMenu *options = new OptionsMenu();
        options->setResolution(Size(512, 640));
        nextScene = options;
    }
}

void MainMenu::onExit(BOOL clicked)
{
    if (clicked)
    {
        setMenuFocus(_btnExit);
        nextScene = NULL;
    }
}

///////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////

void MainMenu::createObjects(void) throw (...)
{
    // TODO : order IS VERY IMPORTANT, so objects must have a priority in order
    // to make sure that methods like initialize, update, render ... are called
    // correctly

  	///////////////////////////////////////////////////////////////////////////
    // Create the TEXTURE
    ///////////////////////////////////////////////////////////////////////////
    GameObject *texture = new GameObject(this, "Logo", "", HUD_LEVEL);
    // Create its components
    Transformation *texTransf = new Transformation(texture, 256.0, 450.0, 
        0.0, 0.0, 1.0, 1.0);
    PlainTexture *texTexture = new PlainTexture(texture, "logo2.png", GL_RGBA, true);
    // Add components to object
    texture->addComponent(texTransf);
    texture->addComponent(texTexture);

  	///////////////////////////////////////////////////////////////////////////
    // Create the BUTTONS
    ///////////////////////////////////////////////////////////////////////////
    _btnPlay = new PushButton(this, "PlayButton", "Button", HUD_LEVEL);
    _btnPlay->setText("PLAY");
    _btnPlay->setFont(TIMES_ROMAN_24);
    _btnPlay->setPosition(Point(210.0f, 310.0f));
    _btnPlay->setSize(Size(60.0f, 20.0f));
    _btnPlay->setDefault(true);

    _btnOptions = new PushButton(this, "OptionsButton", "Button", HUD_LEVEL);
    _btnOptions->setText("OPTIONS");
    _btnOptions->setFont(TIMES_ROMAN_24);
    _btnOptions->setPosition(Point(210.0f, 260.0f));
    _btnOptions->setSize(Size(105.0f, 20.0f));

    _btnExit = new PushButton(this, "ExitButton", "Button", HUD_LEVEL);
    _btnExit->setText("EXIT");
    _btnExit->setFont(TIMES_ROMAN_24);
    _btnExit->setPosition(Point(210.0f, 210.0f));
    _btnExit->setSize(Size(55.0f, 20.0f));
    
    addObject(texture);
    addObject(_btnPlay);
    addObject(_btnOptions);
    addObject(_btnExit);

    _widgets.push_back(_btnPlay);
    _widgets.push_back(_btnOptions);
    _widgets.push_back(_btnExit);
}

void MainMenu::setMenuFocus(PushButton *btn)
{
    vector<Widget*>::const_iterator it;
    for (it=_widgets.begin(); it<_widgets.end(); it++)
    {
        if (btn == dynamic_cast<PushButton*>(*it))
        {
            (*it)->setFocus(true);
        }
        else
        {
            (*it)->setFocus(false);
        }
    }
}

///////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////

PushButton* MainMenu::btnPlay(void) const
{
    return _btnPlay;
}

PushButton* MainMenu::btnOptions(void) const
{
    return _btnOptions;
}

PushButton* MainMenu::btnExit(void) const
{
    return _btnExit;
}

const vector<Widget*>& MainMenu::widgets(void) const
{
    return _widgets;
}
